<?php
/**
 *
 * User:xinhuazhang
 * Date:2024/4/5
 * TIPS:功能说明
 * Email:<1655626823@qq.com>
 */

namespace app\api\controller;

use app\admin\model\User;
use app\common\controller\Api;
use app\common\controller\Frontend;
use app\common\library\xmwechat\offiaccount\OaService;
use app\common\model\imchat\Friends;
use app\common\model\Wxinfo;
use ba\Exception;
use GatewayWorker\Lib\Gateway;
use think\facade\Cookie;
use think\facade\Db;
use think\Validate;
use app\common\model\imchat\RoomUser;
use app\common\model\imchat\Room;
use app\common\model\imchat\Message;

#[Apidoc\Title("聊天接口")]
class Imchat extends Frontend
{
    protected array $noNeedLogin = [''];

    protected array $noNeedPermission = ['*']; // 无需检查权限的接口 $noNeedLogin

    /**
     * 限制已登录
     */
    public function _initialize()
    {

    }

    /**
     * 首页 用于测试
     */
    public function index()
    {
    }

    #[
        Apidoc\Title("聊天用户列表 以及 未读信息unread_msg"),
        Apidoc\Tag("apidoc,基础,示例"),
        Apidoc\Method("GET"),
        Apidoc\Url("/api/imchat/chatList"),
        Apidoc\Returned("unread_msg", type: "int", desc: "未读信息"),
        Apidoc\Returned("user_list", type: "array", desc: "用户列表"),
        Apidoc\Returned("user_list.unread_count", type: "int", desc: "未读数量"),
        Apidoc\Returned("user_list.last_message", type: "int", desc: "最后一条记录"),
        Apidoc\Returned("user_list.nickname", type: "string", desc: "昵称"),
        Apidoc\Returned("user_list.last_time", type: "string", desc: "最后时间"),
        Apidoc\Returned("user_list.unread_count", type: "string", desc: "未读数量·"),
    ]
    public function chatList()
    {
        if ($this->auth->isLogin()) {
            // 找出可以聊天的所有用户
            $users = RoomUser::getChatUsersList($this->auth->id);
            // 找出加入的所有群组
            // $chat_group = Room::getChatGroup($this->auth->id);
            // 找出此人所有的未读信息 放到最近聊天名单
            $rec_chat = Message::getNoReadByUser($this->auth->id);
            $chat_record = Message::getNoReadMsg($rec_chat, $this->auth->id);
            $ret = [
                'user_list' => $users,
                'unread_msg' => count($chat_record),
                //'chat_group' => $chat_group,
//            'rec_chat' => $rec_chat,
                // 'chat_record' => $chat_record,
            ];
            $this->success('', $ret);
        } else {
            $this->success('', [
                'user_list' => [],
                'unread_msg' => 0,
                'status' => '未登录'
            ]);
        }
    }

    /**
     * 获取用户信息以及凭证 socket地址
     * @return json
     */
    #[
        Apidoc\Title("1、先请求获取用户信息以及凭证 socket地址"),
        Apidoc\Method("GET"),
        Apidoc\Url("/api/imchat/cert"),
        Apidoc\Returned("id", type: "int", desc: "Id"),
    ]
    public function cert()
    {
//        $cert = time() . array_reduce(range(1, 158), function ($v1, $v2) {
//                $s = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';
//                return $v1 . $s[rand(0, 61)];
//            });
//        Db::name('imchat_cert')->insert([
//            'cert' => $cert,
//            'expire_time' => time() + 10 //10秒内有效
//        ]);
        // 几率删除以前的
        if (rand(0, 100) == 1) {
            Db::name('imchat_cert')->whereTime('expire_time', '<=', time())->delete();
        }
        $ret['user'] = [
            'id' => $this->auth->id,
            'username' => $this->auth->username,
            'nickname' => $this->auth->nickname,
            'avatar' => $this->auth->avatar,

        ];
        $ret['socket_addr'] = "wss://socket.ynbaozugong.com/wss"; // 此处不填的话 由页面自动提取
        $this->success('', $ret);
    }

    /**
     * 为websocket绑定用户
     */
    #[
        Apidoc\Title("2再为websocket绑定用户"),
        Apidoc\Method("POST"),
        Apidoc\Url("/api/imchat/bindWSUser"),
        Apidoc\Param("client_id", type: "string", require: "true", desc: "客户端id"),
        Apidoc\Returned("id", type: "int", desc: "Id"),
    ]
// Apidoc\Param("cert", type: "string", require: "true", desc: "证书"),
    public function bindWSUser()
    {
        $client_id = $this->request->param('client_id');
        $cert = $this->request->param('cert');
        $cert = time() . array_reduce(range(1, 158), function ($v1, $v2) {
                $s = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';
                return $v1 . $s[rand(0, 61)];
            });
        Db::name('imchat_cert')->insert([
            'cert' => $cert,
            'expire_time' => time() - 20 //10秒内有效
        ]);
        if ($client_id && $cert) {
            // 先判断是否有绑定权限
            $where = [['cert', '=', $cert],
                ['expire_time', '<=', time()]
            ];
            $has = Db::name('imchat_cert')->where($where)->find();
            if ($has) {
                try {
                    // 执行uid绑定
                    Gateway::bindUid($client_id, $this->auth->id);
                    // 群组加入
                    foreach (RoomUser::getRoomIdByUser($this->auth->id) as $value) {
                        Gateway::joinGroup($client_id, $value);
                    }
                    //删除
                    Db::name('imchat_cert')->where($where)->delete();
                } catch (\Exception $e) {
                    $this->error($e->getMessage());
                }
                $this->success('绑定成功');
            }
        }

        $this->error('绑定失败', [$client_id, $cert]);
    }

    /**
     *
     */
    #[
        Apidoc\Title("3、发送文本信息"),
        Apidoc\Method("POST"),
        Apidoc\Url("/api/imchat/sendTxtMsg"),
        Apidoc\Param("to_uid", type: "int", require: "true", desc: "接收者id"),
        Apidoc\Param("content", type: "string", require: "true", desc: " 支持div标签消息内容"),
        Apidoc\Param("type", type: "string", require: "true", desc: "普通文本0，1房源信息id ,2 找房信息id3图片4视频 "),
        Apidoc\Query("id", type: "int", desc: "Id"),
    ]
    public function sendTxtMsg()
    {
        $data = $this->request->post();
        $data['content'] = json_decode(file_get_contents('php://input'), true)['content'];
        $data['type'] = $this->request->param('type', 0);
        $data['from_uid'] = $this->auth->id;
        $validate = \think\facade\Validate::rule([
            'from_uid' => 'require|number',
            'to_uid' => 'require|number',
            'content' => 'require|max:1000',
        ]);
        if ($data['to_uid'] == $this->auth->id) {
            $this->error('不能给自己发消息');
        }
        if (!$validate->check($data)) {
            $this->error($validate->getError());
        }
        if ($this->auth->id != $data['to_uid'] && !(new Friends())->where(['from_uid' => $this->auth->id, 'to_uid' => $data['to_uid']])->find()) {
            (new Friends())->create(['from_uid' => $this->auth->id, 'to_uid' => $data['to_uid']]);
            (new Friends())->create(['from_uid' => $data['to_uid'], 'to_uid' => $this->auth->id]);
        }
        // 插入
        $ret = Message::insertMsg($data, $this->auth->id);
        try {
            $user_id = $data['to_uid'];
            $unionid = (new User())->where('id', '=', $user_id)->value('weixin_unionid');
            $openid = (new Wxinfo())->where(['unionid' => $unionid])->value('wxopenid');// 'oyMrVspaMfT-QfD0qjaU7W-_1tBU';
            $last_time = (new Message())->where(['to_uid'=> $user_id])->order('id', 'desc')->value('createtime');
            $timeer = time() - $last_time;
            //如果timer 10 分钟 时间内有发送过消息，则不发送模板消息
            if ($openid && $timeer > 6 * 3600) {
                $template_id = '10dAODMpbdJIXUt0oiNt7bYPaNpwTQ72nsq42JefLro';
                $data = [
                    'thing1' => ['value' => '您有新的消息待查看，请前往小程序查看', 'color' => '#888888'],
                    'thing11' => ['value' => $this->auth->nickname, 'color' => '#888888'],
                ];
                // 模板跳转链接,不跳转可忽略此参数
                $url = '';
                // 跳小程序所需数据,不需跳小程序可不用传该数据，小程序appid必须已绑定关联当前公众号
                $miniprogram = [
                    'appid' => 'wx2b1b3222bf4cab2b',
                    'pagepath' => 'pages/message/index'
                ];
                (new OaService())->sendTemplateMessage($openid, $template_id, $data, $url, $miniprogram);
            }
        } catch (Exception $exception) {

        }
        $ret ? $this->success($this->auth->id . '发送成功') : $this->error('发送失败');
    }


    public function msgList()
    {
        $lists = (new Message())->field('id,content,type,createtime,status')
            ->where([
                'from_uid' => $this->auth->id,
                'to_uid' => $this->request->param('to_uid'),
            ])
            ->order('createtime desc')
            ->paginate();
        (new Message())->where([
            'from_uid' => $this->request->param('to_uid'),
            'to_uid' => $this->auth->id,
        ])->update(['status' => 1]);
        $touser = (new \app\admin\model\User())->where('id', $this->request->param('to_uid'))->field('id,uuid,nickname,avatar,mobile')->find();
        $this->success('聊天信息', [
            'lists' => $lists,
            'touser' => $touser
        ]);
    }

    private function json($data = [], $errno = 0, $msg = 'ok')
    {
        if ($errno == 0) {
            $this->error($msg, $data);
        } else {
            $this->success($msg, $data);
        }
        if (is_array($data) && $data) {
            return json([
                'errno' => $errno,
                'msg' => $msg, 'code' => $errno,
                'data' => $data,
            ]);
        }
        $_errno = $errno;
        $errno = $data ? $data : $errno;
        $msg = $_errno !== 0 ? $_errno : $msg;
        return json([
            'errno' => $errno,
            'msg' => $msg,
            'code' => $errno,
        ]);
    }


    /**
     * 获取聊天记录
     */
    #[
        Apidoc\Title("2.1聊天记录列表"),
        Apidoc\Method("POST"),
        Apidoc\Url("/api/imchat/getHistoryChatRecord"),
        Apidoc\Param("from_uid", type: "int", require: "true", desc: "来源用户id"),
        Apidoc\Query("page", type: "int", desc: "Id"),
        Apidoc\Returned("userInfo.domain_avatar", type: "array", desc: "domain_avatar 用户信息 带域名头像"),
        Apidoc\Returned("userInfo.domain_avatar", type: "array", desc: "domain_avatar 用户信息 带域名头像"),
        Apidoc\Returned("userInfo.nickname", type: "array", desc: "nickname 用户信息 带域名头像"),
        Apidoc\Returned("content", type: "string", desc: "原消息内容"),
        Apidoc\Returned("from_uid", type: "int", desc: "等于当前用户id在右边，等于to_uid在左边"),
        Apidoc\Returned("content_extra", type: "array", desc: "扩展消息内容（按照type 普通文本0，1房源信息id ,2 找房信息id3图片4视频 ）返回数组 5默认打招呼信息"),
    ]
    public function getHistoryChatRecord()
    {
        $data = input("post.");
        if (!isset($data['msg_id'])) {
            $data['msg_id'] = isset($data['msg_id']) ? (int)$data['msg_id'] : 0;
        }
        $rule = [
            'from_uid' => 'require|number',
        ];
        $result = $this->validate($data, $rule);
        if ($result !== true) {
            $this->error($result);
        }
        $data['id'] = $data['from_uid'];
        $data['type'] = 'user';

        $where['to_uid'] = $this->auth->id;
        $where['from_uid'] = $data['from_uid'];
        $from_uid = $data['from_uid'];
        $to_uid = $this->auth->id;

        if ((new Message())
                ->field('id msg_id,to_uid, from_uid, content, createtime,type,status')
                ->where(function ($query) use ($from_uid, $to_uid) {
                    $query->where(['to_uid' => $to_uid, 'from_uid' => $from_uid]);
                })
                ->whereOr(function ($query) use ($from_uid, $to_uid) {
                    $query->where(['to_uid' => $from_uid, 'from_uid' => $to_uid]);
                })->count() <= 0) {
            if ($from_uid != $to_uid) {
                $first_msg = Message::insertMsg([
                    'from_uid' => $from_uid,
                    'to_uid' => $to_uid,
                    'type' => 5,
                    'content' => '你好，很高兴认识你。',
                ], $this->auth->id);
            }
        }

        $_rt = (new Message())
            ->field('id msg_id,to_uid, from_uid, content, createtime,type,status')
            ->where(function ($query) use ($from_uid, $to_uid) {
                $query->where(['to_uid' => $to_uid, 'from_uid' => $from_uid]);
            })
            ->whereOr(function ($query) use ($from_uid, $to_uid) {
                $query->where(['to_uid' => $from_uid, 'from_uid' => $to_uid]);
            })
            ->with(['fromUser'])
            ->order('msg_id', 'DESC')
            ->paginate();
        (new Message())->where([
            'from_uid' => $this->request->param('from_uid'),
            'to_uid' => $this->auth->id,
        ])->update(['status' => 1]);
        $msg_list = $_rt->items();
        $ret['data'] = array_map(function ($v) {
            $v->visible(['fromUser.domain_avatar', 'fromUser.nickname', 'fromUser.id', 'fromUser.uuid', 'fromUser.mobile']);
            return $v->toArray();
        }, $msg_list);
        $ret_data = array_reverse($ret['data']);

        $result = [
            "total" => $_rt->total(),
            "per_page" => $_rt->listRows(),
            "current_page" => $_rt->currentPage(),
            "last_page" => $_rt->lastPage(),
            'data' => $ret_data,
        ];
        return $this->success('聊天记录列表', $result);
    }

    /**
     * 已读标记
     */
    public function setRead()
    {
        $data = input("post.");
        $rule = [
            'id' => 'require|number',
        ];
        $result = $this->validate($data, $rule);
        if ($result !== true) {
            return $this->json(500, $result);
        }
        Message::setRead($this->auth->id, $data['id'], $data['type']);
    }

    /**
     * 上传文件或者图片 没有做权限处理 没有考虑用户能否下载问题
     * 没有保留源文件名
     * @return [type] [description]
     */
    public function upload_file()
    {

        $file = request()->file('file');
        if (!$file) {
            return $this->json(403, '没有选择文件或者文件过大');
        }
        // 文件类型是文件还是图片
        $type = in_array($file->getFileInfo()['type'], ['image/gif', 'image/jpeg', 'image/png']) ? 'image' : 'file';
        // 保存路径 注意目录有没有 或者有没有操作权限
        $path = __DIR__ . 'public' . DIRECTORY_SEPARATOR . 'uploads' . DIRECTORY_SEPARATOR . 'imchat';
        if (!file_exists($path)) {
            mkdir($path, 0777, true);
        }
        // 10m限制
        $info = $file->isValid(['size' => 1024 * 1024 * 10])->move($path);
        if ($info) {
            $sn = str_replace('\\', '/', $info->getSaveName());
            if ($type == 'image') {
                // 拼接图片显示字符串
                $sn = '/uploads/imchat/' . $sn;
                $re_str = "<img src='{$sn}'>";
            } else {
                $sn = '/addons/imchat/index/download_file?name=' . $sn;
                $re_str = <<<Eof
<div style="font-size: 12px;color: #aaa;">文件</div>
<div style="align-items: center;display: flex;">
  <span class="iconfont icon-3801wenjian" style="font-size: 28px;"></span>
  <a href="{$sn}" style="cursor: pointer;margin-left: 5px;">点击下载</a>
</div>
Eof;
            }
            // 发送消息
            $data = input('post.');
            $data['content'] = $re_str;
            $_ret = Message::insertMsg($data, $this->auth->id);
            if ($_ret) {
                return $this->json($_ret);
            }
            return $this->json(500, '发送失败');
        } else {
            return $this->json(500, $file->getError());
        }
    }

    /**
     * 文件下载
     */
    public function download_file()
    {
        $f = $_REQUEST['name'];
        if (!$f) {
            die('404');
        }
        $name = explode('/', $f);
        $name = end($name);

        $file_name = getcwd() . '/uploads/imchat/' . $f;
        if (!file_exists($file_name)) {
            die;
        }
        $file = fopen($file_name, "r");
        header("Content-Type: application/octet-stream");
        header("Accept-Ranges: bytes");
        header("Accept-Length: " . filesize($file_name));
        header("Content-Disposition: attachment; filename=" . $name);
        echo fread($file, filesize($file_name));
        fclose($file);
    }
}
